/*
 * cxxomfort example: random, foreach
 *
 * This program provides sample usage of the
 * "foreach loop" emulation feature.
 */

//#define CXXOMFORT_NOTICES 1
#include <cxxomfort/backports.hpp>
#include <cxxomfort/random.hpp>
#include <cxxomfort/library/random.hpp>
//#include <cxxomfort/library/foreach.hpp> // foreach
#include <cxxomfort/library/type_name.hpp>
#include <cxxomfort/library/numeric.hpp> // make_unsigned
#include <cxxomfort/library/fixed_vector.hpp>
#include <cxxomfort/library/type_name.hpp>
#include <vector>
#include <list>
#include <deque>
#include <iterator>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <ctime> // time (), srand ()

/*
 * The demonstration consists of:
 *
 * * generating an amount {LIM} of random numbers
 * * setting up a functoid that will "tick" with 1/{PQ} probability when invoked
 * * iteratively erase from the list with the above probability functoid
 * * until there's at most {LLOW} elements left
 *
 */

const unsigned int LIM = 1000;
const unsigned int LLOW = 20;
const int NMAX = 0x8000;
const unsigned PQ = 1;
const unsigned PR= 9;


struct gen {
    std::minstd_rand ms;
    std::mt19937 mt;
    std::ranlux24_base r24b;
    // msvc shuffle_order_engine is broken so we use a different knuth_b
    cxxomfort::fix::knuth_b kn;
};

// pq_selector
const struct pq_selector_t {
    bool operator() (int) const {
        double pq= ((double)rand()/RAND_MAX);
        return pq * PR < PQ;
    }
} pqs = {};

namespace num= cxxomfort::library::numeric;
namespace ran= cxxomfort::library::random;

int main () {
    using namespace std;
    cxxomfort::output_info(stdout); cout<< endl;

    srand (time(0));
    cout<< "COUNTER "<< hex<< __COUNTER__<< dec<< endl;

    random_device rd;
    
    // example containers
    vector<unsigned short> ve (LIM);
    list<unsigned short> li (LIM);
    //forward_list<unsigned short> fl (LIM);
    deque<unsigned short> dq (LIM);
    cxxomfort::library::fixed_vector<unsigned short> fve (LIM);
	#define THISSEQ() dq 
	cout<< "Selected sequence is: "<< cxxomfort::library::typeid_demangle(typeid(THISSEQ()))<< endl;

    CXXO_I12N_SEQ( vector<short>, samples, {1, -1, 2, -2, 3, -3, 4, -4, 5, -5 });
    
    vector<unsigned short> seq (LIM);
    
    // example generators
    
    minstd_rand0 rg_0 (time(0));
    ranlux24_base rg_r (time(0));
    ranlux48_base rg_r2 (time(0));
    ran::icg0 rg_inv (time(0));
    cxxomfort::fix::knuth_b rg_k( num::to_unsigned(time(0)) ^ CXXOMFORT_COMPILER_VERSION );
    #define THISRNG() rg_inv


    uniform_int_distribution<unsigned short> dis(1, NMAX);

    // generate a list of {LIM} elements obtained from one of the
    // software generators
    //function<unsigned short()> rn = cxxomfort::library::make_random_wrap(dis, mt);

	
    generate(begin(THISSEQ()), end(THISSEQ()), bind(dis, THISRNG() ) );
    CXXO_FOREACH (int n, THISSEQ() ) { cout<< hex<< n<< "  "; }
    cout<< dec<< endl;

    // filter the sequence with a selector that has
    // probability 0 < PQ/PR < 1 of matching
    // filter sequence x times until less than {LLOW} elements remain
    size_t pass= 0;
    size_t oldsize= size(THISSEQ()), newsize= oldsize;
    while (size(THISSEQ()) >= LLOW) {
        //vector<unsigned short>::iterator ;
        THISSEQ().erase( remove_if(begin(THISSEQ()), end(THISSEQ()), pqs), end(THISSEQ()));
        oldsize= newsize;
        newsize= seq.size();
        ++pass;
        cout<< "Pass "<< setw(3)<< pass<< "  Reduced "
        << static_cast<int>(((double)newsize/oldsize)*100)<< "%  "
        << "Remain "<< size(THISSEQ())<< endl;
    }

    CXXO_FOREACH (int n, THISSEQ() ) { cout<< hex<< n<< "  "; }
    cout<< endl;

}

